#if 1
#include "track_4y_500fps.h"
#include <openssl/aes.h>
#include <fstream>
#include <cstdio>
#include <iostream>
#include <cstring>
#include <unistd.h>

static float window_track_4y_500fps[289]={
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0014485813926750633 ,
        0.0055737921850884985 ,
        0.011747606429224311 ,
        0.019030116872178315 ,
        0.02631262731513232 ,
        0.03248644155926813 ,
        0.03661165235168157 ,
        0.03806023374435663 ,
        0.03661165235168157 ,
        0.03248644155926813 ,
        0.02631262731513232 ,
        0.019030116872178315 ,
        0.011747606429224311 ,
        0.0055737921850884985 ,
        0.0014485813926750633 ,
        0.0 ,
        0.0 ,
        0.0055737921850884985 ,
        0.02144660940672625 ,
        0.04520195913036531 ,
        0.07322330470336313 ,
        0.10124465027636097 ,
        0.12500000000000003 ,
        0.14087281722163777 ,
        0.14644660940672627 ,
        0.14087281722163777 ,
        0.12500000000000003 ,
        0.10124465027636097 ,
        0.07322330470336313 ,
        0.04520195913036531 ,
        0.02144660940672625 ,
        0.0055737921850884985 ,
        0.0 ,
        0.0 ,
        0.011747606429224311 ,
        0.04520195913036531 ,
        0.09526993616913669 ,
        0.15432914190872757 ,
        0.21338834764831846 ,
        0.26345632468708985 ,
        0.29691067738823085 ,
        0.30865828381745514 ,
        0.29691067738823085 ,
        0.26345632468708985 ,
        0.21338834764831846 ,
        0.15432914190872757 ,
        0.09526993616913669 ,
        0.04520195913036531 ,
        0.011747606429224311 ,
        0.0 ,
        0.0 ,
        0.019030116872178315 ,
        0.07322330470336313 ,
        0.15432914190872757 ,
        0.25 ,
        0.34567085809127246 ,
        0.42677669529663687 ,
        0.4809698831278217 ,
        0.5 ,
        0.4809698831278217 ,
        0.42677669529663687 ,
        0.34567085809127246 ,
        0.25 ,
        0.15432914190872757 ,
        0.07322330470336313 ,
        0.019030116872178315 ,
        0.0 ,
        0.0 ,
        0.02631262731513232 ,
        0.10124465027636097 ,
        0.21338834764831846 ,
        0.34567085809127246 ,
        0.4779533685342265 ,
        0.5900970659061839 ,
        0.6650290888674126 ,
        0.6913417161825449 ,
        0.6650290888674126 ,
        0.5900970659061839 ,
        0.4779533685342265 ,
        0.34567085809127246 ,
        0.21338834764831846 ,
        0.10124465027636097 ,
        0.02631262731513232 ,
        0.0 ,
        0.0 ,
        0.03248644155926813 ,
        0.12500000000000003 ,
        0.26345632468708985 ,
        0.42677669529663687 ,
        0.5900970659061839 ,
        0.7285533905932737 ,
        0.8210669490340056 ,
        0.8535533905932737 ,
        0.8210669490340056 ,
        0.7285533905932737 ,
        0.5900970659061839 ,
        0.42677669529663687 ,
        0.26345632468708985 ,
        0.12500000000000003 ,
        0.03248644155926813 ,
        0.0 ,
        0.0 ,
        0.03661165235168157 ,
        0.14087281722163777 ,
        0.29691067738823085 ,
        0.4809698831278217 ,
        0.6650290888674126 ,
        0.8210669490340056 ,
        0.9253281139039617 ,
        0.9619397662556434 ,
        0.9253281139039617 ,
        0.8210669490340056 ,
        0.6650290888674126 ,
        0.4809698831278217 ,
        0.29691067738823085 ,
        0.14087281722163777 ,
        0.03661165235168157 ,
        0.0 ,
        0.0 ,
        0.03806023374435663 ,
        0.14644660940672627 ,
        0.30865828381745514 ,
        0.5 ,
        0.6913417161825449 ,
        0.8535533905932737 ,
        0.9619397662556434 ,
        1.0 ,
        0.9619397662556434 ,
        0.8535533905932737 ,
        0.6913417161825449 ,
        0.5 ,
        0.30865828381745514 ,
        0.14644660940672627 ,
        0.03806023374435663 ,
        0.0 ,
        0.0 ,
        0.03661165235168157 ,
        0.14087281722163777 ,
        0.29691067738823085 ,
        0.4809698831278217 ,
        0.6650290888674126 ,
        0.8210669490340056 ,
        0.9253281139039617 ,
        0.9619397662556434 ,
        0.9253281139039617 ,
        0.8210669490340056 ,
        0.6650290888674126 ,
        0.4809698831278217 ,
        0.29691067738823085 ,
        0.14087281722163777 ,
        0.03661165235168157 ,
        0.0 ,
        0.0 ,
        0.03248644155926813 ,
        0.12500000000000003 ,
        0.26345632468708985 ,
        0.42677669529663687 ,
        0.5900970659061839 ,
        0.7285533905932737 ,
        0.8210669490340056 ,
        0.8535533905932737 ,
        0.8210669490340056 ,
        0.7285533905932737 ,
        0.5900970659061839 ,
        0.42677669529663687 ,
        0.26345632468708985 ,
        0.12500000000000003 ,
        0.03248644155926813 ,
        0.0 ,
        0.0 ,
        0.02631262731513232 ,
        0.10124465027636097 ,
        0.21338834764831846 ,
        0.34567085809127246 ,
        0.4779533685342265 ,
        0.5900970659061839 ,
        0.6650290888674126 ,
        0.6913417161825449 ,
        0.6650290888674126 ,
        0.5900970659061839 ,
        0.4779533685342265 ,
        0.34567085809127246 ,
        0.21338834764831846 ,
        0.10124465027636097 ,
        0.02631262731513232 ,
        0.0 ,
        0.0 ,
        0.019030116872178315 ,
        0.07322330470336313 ,
        0.15432914190872757 ,
        0.25 ,
        0.34567085809127246 ,
        0.42677669529663687 ,
        0.4809698831278217 ,
        0.5 ,
        0.4809698831278217 ,
        0.42677669529663687 ,
        0.34567085809127246 ,
        0.25 ,
        0.15432914190872757 ,
        0.07322330470336313 ,
        0.019030116872178315 ,
        0.0 ,
        0.0 ,
        0.011747606429224311 ,
        0.04520195913036531 ,
        0.09526993616913669 ,
        0.15432914190872757 ,
        0.21338834764831846 ,
        0.26345632468708985 ,
        0.29691067738823085 ,
        0.30865828381745514 ,
        0.29691067738823085 ,
        0.26345632468708985 ,
        0.21338834764831846 ,
        0.15432914190872757 ,
        0.09526993616913669 ,
        0.04520195913036531 ,
        0.011747606429224311 ,
        0.0 ,
        0.0 ,
        0.0055737921850884985 ,
        0.02144660940672625 ,
        0.04520195913036531 ,
        0.07322330470336313 ,
        0.10124465027636097 ,
        0.12500000000000003 ,
        0.14087281722163777 ,
        0.14644660940672627 ,
        0.14087281722163777 ,
        0.12500000000000003 ,
        0.10124465027636097 ,
        0.07322330470336313 ,
        0.04520195913036531 ,
        0.02144660940672625 ,
        0.0055737921850884985 ,
        0.0 ,
        0.0 ,
        0.0014485813926750633 ,
        0.0055737921850884985 ,
        0.011747606429224311 ,
        0.019030116872178315 ,
        0.02631262731513232 ,
        0.03248644155926813 ,
        0.03661165235168157 ,
        0.03806023374435663 ,
        0.03661165235168157 ,
        0.03248644155926813 ,
        0.02631262731513232 ,
        0.019030116872178315 ,
        0.011747606429224311 ,
        0.0055737921850884985 ,
        0.0014485813926750633 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
        0.0 ,
};

static float xy_ctr_track_4y_500fps[289*2]={
        87.0 ,
        87.0 ,
        95.0 ,
        87.0 ,
        103.0 ,
        87.0 ,
        111.0 ,
        87.0 ,
        119.0 ,
        87.0 ,
        127.0 ,
        87.0 ,
        135.0 ,
        87.0 ,
        143.0 ,
        87.0 ,
        151.0 ,
        87.0 ,
        159.0 ,
        87.0 ,
        167.0 ,
        87.0 ,
        175.0 ,
        87.0 ,
        183.0 ,
        87.0 ,
        191.0 ,
        87.0 ,
        199.0 ,
        87.0 ,
        207.0 ,
        87.0 ,
        215.0 ,
        87.0 ,
        87.0 ,
        95.0 ,
        95.0 ,
        95.0 ,
        103.0 ,
        95.0 ,
        111.0 ,
        95.0 ,
        119.0 ,
        95.0 ,
        127.0 ,
        95.0 ,
        135.0 ,
        95.0 ,
        143.0 ,
        95.0 ,
        151.0 ,
        95.0 ,
        159.0 ,
        95.0 ,
        167.0 ,
        95.0 ,
        175.0 ,
        95.0 ,
        183.0 ,
        95.0 ,
        191.0 ,
        95.0 ,
        199.0 ,
        95.0 ,
        207.0 ,
        95.0 ,
        215.0 ,
        95.0 ,
        87.0 ,
        103.0 ,
        95.0 ,
        103.0 ,
        103.0 ,
        103.0 ,
        111.0 ,
        103.0 ,
        119.0 ,
        103.0 ,
        127.0 ,
        103.0 ,
        135.0 ,
        103.0 ,
        143.0 ,
        103.0 ,
        151.0 ,
        103.0 ,
        159.0 ,
        103.0 ,
        167.0 ,
        103.0 ,
        175.0 ,
        103.0 ,
        183.0 ,
        103.0 ,
        191.0 ,
        103.0 ,
        199.0 ,
        103.0 ,
        207.0 ,
        103.0 ,
        215.0 ,
        103.0 ,
        87.0 ,
        111.0 ,
        95.0 ,
        111.0 ,
        103.0 ,
        111.0 ,
        111.0 ,
        111.0 ,
        119.0 ,
        111.0 ,
        127.0 ,
        111.0 ,
        135.0 ,
        111.0 ,
        143.0 ,
        111.0 ,
        151.0 ,
        111.0 ,
        159.0 ,
        111.0 ,
        167.0 ,
        111.0 ,
        175.0 ,
        111.0 ,
        183.0 ,
        111.0 ,
        191.0 ,
        111.0 ,
        199.0 ,
        111.0 ,
        207.0 ,
        111.0 ,
        215.0 ,
        111.0 ,
        87.0 ,
        119.0 ,
        95.0 ,
        119.0 ,
        103.0 ,
        119.0 ,
        111.0 ,
        119.0 ,
        119.0 ,
        119.0 ,
        127.0 ,
        119.0 ,
        135.0 ,
        119.0 ,
        143.0 ,
        119.0 ,
        151.0 ,
        119.0 ,
        159.0 ,
        119.0 ,
        167.0 ,
        119.0 ,
        175.0 ,
        119.0 ,
        183.0 ,
        119.0 ,
        191.0 ,
        119.0 ,
        199.0 ,
        119.0 ,
        207.0 ,
        119.0 ,
        215.0 ,
        119.0 ,
        87.0 ,
        127.0 ,
        95.0 ,
        127.0 ,
        103.0 ,
        127.0 ,
        111.0 ,
        127.0 ,
        119.0 ,
        127.0 ,
        127.0 ,
        127.0 ,
        135.0 ,
        127.0 ,
        143.0 ,
        127.0 ,
        151.0 ,
        127.0 ,
        159.0 ,
        127.0 ,
        167.0 ,
        127.0 ,
        175.0 ,
        127.0 ,
        183.0 ,
        127.0 ,
        191.0 ,
        127.0 ,
        199.0 ,
        127.0 ,
        207.0 ,
        127.0 ,
        215.0 ,
        127.0 ,
        87.0 ,
        135.0 ,
        95.0 ,
        135.0 ,
        103.0 ,
        135.0 ,
        111.0 ,
        135.0 ,
        119.0 ,
        135.0 ,
        127.0 ,
        135.0 ,
        135.0 ,
        135.0 ,
        143.0 ,
        135.0 ,
        151.0 ,
        135.0 ,
        159.0 ,
        135.0 ,
        167.0 ,
        135.0 ,
        175.0 ,
        135.0 ,
        183.0 ,
        135.0 ,
        191.0 ,
        135.0 ,
        199.0 ,
        135.0 ,
        207.0 ,
        135.0 ,
        215.0 ,
        135.0 ,
        87.0 ,
        143.0 ,
        95.0 ,
        143.0 ,
        103.0 ,
        143.0 ,
        111.0 ,
        143.0 ,
        119.0 ,
        143.0 ,
        127.0 ,
        143.0 ,
        135.0 ,
        143.0 ,
        143.0 ,
        143.0 ,
        151.0 ,
        143.0 ,
        159.0 ,
        143.0 ,
        167.0 ,
        143.0 ,
        175.0 ,
        143.0 ,
        183.0 ,
        143.0 ,
        191.0 ,
        143.0 ,
        199.0 ,
        143.0 ,
        207.0 ,
        143.0 ,
        215.0 ,
        143.0 ,
        87.0 ,
        151.0 ,
        95.0 ,
        151.0 ,
        103.0 ,
        151.0 ,
        111.0 ,
        151.0 ,
        119.0 ,
        151.0 ,
        127.0 ,
        151.0 ,
        135.0 ,
        151.0 ,
        143.0 ,
        151.0 ,
        151.0 ,
        151.0 ,
        159.0 ,
        151.0 ,
        167.0 ,
        151.0 ,
        175.0 ,
        151.0 ,
        183.0 ,
        151.0 ,
        191.0 ,
        151.0 ,
        199.0 ,
        151.0 ,
        207.0 ,
        151.0 ,
        215.0 ,
        151.0 ,
        87.0 ,
        159.0 ,
        95.0 ,
        159.0 ,
        103.0 ,
        159.0 ,
        111.0 ,
        159.0 ,
        119.0 ,
        159.0 ,
        127.0 ,
        159.0 ,
        135.0 ,
        159.0 ,
        143.0 ,
        159.0 ,
        151.0 ,
        159.0 ,
        159.0 ,
        159.0 ,
        167.0 ,
        159.0 ,
        175.0 ,
        159.0 ,
        183.0 ,
        159.0 ,
        191.0 ,
        159.0 ,
        199.0 ,
        159.0 ,
        207.0 ,
        159.0 ,
        215.0 ,
        159.0 ,
        87.0 ,
        167.0 ,
        95.0 ,
        167.0 ,
        103.0 ,
        167.0 ,
        111.0 ,
        167.0 ,
        119.0 ,
        167.0 ,
        127.0 ,
        167.0 ,
        135.0 ,
        167.0 ,
        143.0 ,
        167.0 ,
        151.0 ,
        167.0 ,
        159.0 ,
        167.0 ,
        167.0 ,
        167.0 ,
        175.0 ,
        167.0 ,
        183.0 ,
        167.0 ,
        191.0 ,
        167.0 ,
        199.0 ,
        167.0 ,
        207.0 ,
        167.0 ,
        215.0 ,
        167.0 ,
        87.0 ,
        175.0 ,
        95.0 ,
        175.0 ,
        103.0 ,
        175.0 ,
        111.0 ,
        175.0 ,
        119.0 ,
        175.0 ,
        127.0 ,
        175.0 ,
        135.0 ,
        175.0 ,
        143.0 ,
        175.0 ,
        151.0 ,
        175.0 ,
        159.0 ,
        175.0 ,
        167.0 ,
        175.0 ,
        175.0 ,
        175.0 ,
        183.0 ,
        175.0 ,
        191.0 ,
        175.0 ,
        199.0 ,
        175.0 ,
        207.0 ,
        175.0 ,
        215.0 ,
        175.0 ,
        87.0 ,
        183.0 ,
        95.0 ,
        183.0 ,
        103.0 ,
        183.0 ,
        111.0 ,
        183.0 ,
        119.0 ,
        183.0 ,
        127.0 ,
        183.0 ,
        135.0 ,
        183.0 ,
        143.0 ,
        183.0 ,
        151.0 ,
        183.0 ,
        159.0 ,
        183.0 ,
        167.0 ,
        183.0 ,
        175.0 ,
        183.0 ,
        183.0 ,
        183.0 ,
        191.0 ,
        183.0 ,
        199.0 ,
        183.0 ,
        207.0 ,
        183.0 ,
        215.0 ,
        183.0 ,
        87.0 ,
        191.0 ,
        95.0 ,
        191.0 ,
        103.0 ,
        191.0 ,
        111.0 ,
        191.0 ,
        119.0 ,
        191.0 ,
        127.0 ,
        191.0 ,
        135.0 ,
        191.0 ,
        143.0 ,
        191.0 ,
        151.0 ,
        191.0 ,
        159.0 ,
        191.0 ,
        167.0 ,
        191.0 ,
        175.0 ,
        191.0 ,
        183.0 ,
        191.0 ,
        191.0 ,
        191.0 ,
        199.0 ,
        191.0 ,
        207.0 ,
        191.0 ,
        215.0 ,
        191.0 ,
        87.0 ,
        199.0 ,
        95.0 ,
        199.0 ,
        103.0 ,
        199.0 ,
        111.0 ,
        199.0 ,
        119.0 ,
        199.0 ,
        127.0 ,
        199.0 ,
        135.0 ,
        199.0 ,
        143.0 ,
        199.0 ,
        151.0 ,
        199.0 ,
        159.0 ,
        199.0 ,
        167.0 ,
        199.0 ,
        175.0 ,
        199.0 ,
        183.0 ,
        199.0 ,
        191.0 ,
        199.0 ,
        199.0 ,
        199.0 ,
        207.0 ,
        199.0 ,
        215.0 ,
        199.0 ,
        87.0 ,
        207.0 ,
        95.0 ,
        207.0 ,
        103.0 ,
        207.0 ,
        111.0 ,
        207.0 ,
        119.0 ,
        207.0 ,
        127.0 ,
        207.0 ,
        135.0 ,
        207.0 ,
        143.0 ,
        207.0 ,
        151.0 ,
        207.0 ,
        159.0 ,
        207.0 ,
        167.0 ,
        207.0 ,
        175.0 ,
        207.0 ,
        183.0 ,
        207.0 ,
        191.0 ,
        207.0 ,
        199.0 ,
        207.0 ,
        207.0 ,
        207.0 ,
        215.0 ,
        207.0 ,
        87.0 ,
        215.0 ,
        95.0 ,
        215.0 ,
        103.0 ,
        215.0 ,
        111.0 ,
        215.0 ,
        119.0 ,
        215.0 ,
        127.0 ,
        215.0 ,
        135.0 ,
        215.0 ,
        143.0 ,
        215.0 ,
        151.0 ,
        215.0 ,
        159.0 ,
        215.0 ,
        167.0 ,
        215.0 ,
        175.0 ,
        215.0 ,
        183.0 ,
        215.0 ,
        191.0 ,
        215.0 ,
        199.0 ,
        215.0 ,
        207.0 ,
        215.0 ,
        215.0 ,
        215.0 ,
};

#define CUDA_CHECK(status) \
do\
{\
auto ret = (status);\
if (ret != 0)\
{\
std::cerr << "fcpp Cuda failure: " << ret << std::endl;\
abort();\
}\
} while (0)

#define DEVICE 0  // GPU id

class Track4y500FPS::ContainerClass{
public:
    ContainerClass();
    ~ContainerClass();

    void init(cv::Mat& frame, cv::Rect roi);
    cv::Rect update(cv::Mat frame, float &scores);

/**********************************************************************************************************************/
    char* decrypt_engine(std::string decrypt_file, std::string key, size_t& size);

    int cpp_call_shell();

/**********************************************************************************************************************/
    Logger gLogger;

    std::string key = "1422622060246lyzklx1422622060246";

    std::vector<float> target_pos = {0, 0};
    std::vector<float> target_sz = {0, 0};

    cv::Mat im_z_crop;
    cv::Scalar avg_chans;

    float pr_socres = 0;

    cv::Rect track(cv::Mat frame,
                   std::vector<float> target_pos1,
                   std::vector<float> target_sz1,
                   float &scores,
                   bool update_state = true);

    std::vector<float> restrict_box(std::vector<float> tragrect);

    std::vector<float> cxywh2xyxyys(std::vector<float> roi);

    int calculate_s_z();

    cv::Rect cxywh2xywh(std::vector<float> roi);

    std::vector<float> xywh2cxywh(cv::Rect roi); //box_wh
    void get_crop(cv::Mat im,
                  std::vector<float> target_pos,
                  std::vector<float> target_sz,
                  const int z_size1, const int x_size1, float &scale,
                  cv::Scalar avg_chans, float context_amount = 0.5);

    void get_subwindow_tracking(cv::Mat im,
                                std::vector<float> pos,
                                float model_sz,
                                float original_sz,
                                cv::Scalar avg_chans = {0.0, 0.0, 0.0, 0.0});

    std::vector<float> xywh2xyxy(cv::Rect roi);

    std::string template_engine_name = "/home/lx/temp/config/WRBqHdrOkyIDsdRMwRSYLBfaCYEdgxPl";
    std::string track_engine_name = "/home/lx/temp/config/rlNppfkOKcqNnuwSmbUcJISmKtXxvRBJ";
    std::string head_engine_name = "/home/lx/temp/config/TSFzfMfdRsfbnvhFSqWQaeCZFKlOJppR";

    static const int template_output_size = 64 * 6 * 6;
    static const int track_output_size = 64 * 28 * 28;
    static const int head_output_size = 64 * 23 * 23;

    nvinfer1::ICudaEngine *template_engine = nullptr;
    nvinfer1::IExecutionContext *template_context = nullptr;
    nvinfer1::IRuntime *template_runtime = nullptr;
    cudaStream_t template_stream{};
    void *template_buffers[3]{};

    int template_warm_up();

    void template_inference(nvinfer1::IExecutionContext &context,
                            cudaStream_t &stream,
                            void **buffers,
                            int batchSize);

    void destroy_template_stream();


    nvinfer1::ICudaEngine *track_engine = nullptr;
    nvinfer1::IExecutionContext *track_context = nullptr;
    nvinfer1::IRuntime *track_runtime = nullptr;
    cudaStream_t track_stream{};
    void *track_buffers[3]{};

    int track_feature_warm_up();

    void track_inference(nvinfer1::IExecutionContext &context,
                         cudaStream_t &stream,
                         void **buffers,
                         int batchSize);

    void destroy_track_stream();

    nvinfer1::ICudaEngine *head_engine = nullptr;
    nvinfer1::IExecutionContext *head_context = nullptr;
    nvinfer1::IRuntime *head_runtime = nullptr;
    cudaStream_t head_stream{};
    void *head_buffers[5]{};

    int head_feature_warm_up();


    void head_inference(nvinfer1::IExecutionContext &context,
                        cudaStream_t &stream,
                        void **buffers,
                        float *output1,
                        float *output2,
                        float *output3,
                        const int output_size,
                        int batchSize);

    void destroy_head_stream();

    float *fcos_cls_score = new float[289];// 1*score_size*score_size*1
    float *fcos_ctr_score = new float[289];// 1*score_size*score_size*1
    float *offset = new float[4 * 17 * 17];    // 1*4*score_size*score_size need permute for get box
    void get_box_float(float *xy_ctr, float *offsets, float *bboxes);

    float change_float(float r);

    float sz_float(float w, float h);

    float sz_wh_float(float *wh);

    void
    postprocess_score_float(float *score, float *box_wh, std::vector<float> target_sz1, float scale_x, float *best_box);

    std::vector<float> postprocess_box_float(int best_pscore_id,
                                             float score,
                                             float *box_wh,
                                             std::vector<float> target_pos1,
                                             std::vector<float> target_sz1,
                                             float scale_x,
                                             float x_size1,
                                             float penalty
    );

    int
    cudawarpaffine(cudaStream_t stream, cv::Mat image, cv::Mat_<float> mat2x3, float model_sz, cv::Scalar avg_chans);

    TRT::Tensor my_gpu_warpaffine;

    void depthwise_warm_up();

    void depthwise_conv_inference();

    // 计算时间
    long long_time1 = 0;
    long long_time2 = 0;
    long long_time3 = 0;
    long long_time4 = 0;
    long long_time5 = 0;
    // num
    int num = 0;

    /****************************************************************************/
    int ys_best_pscore_id{};
    float ys_best_score{};
    float ys_best_box_wh[4]{};
    float ys_best_penalty{};

    static const int total_stride = 8;
    static const int score_size = 17;
    const int score_output_size = 289;//17*17
    static const int score_offset = 87;
    const float context_amount = 0.5;
    const float test_lr = 0.52;
    const float penalty_k = 0.04;
    const float window_influence = 0.21;

    static const int z_size = 127;
    static const int x_size = 303;
    static const int num_conv3x3 = 2;
    static const int min_w = 10;
    static const int min_h = 10;

    const float AC_SCORE = 0.;//信分数
    cv::Rect bounding_box;

    int im_w = 0;//image width
    int im_h = 0;//image height

    const int dw_x_size = 1 * 64 * 28 * 28;
    const int kernel_size = 1 * 64 * 6 * 6;
    const int dw_o_size = 1 * 64 * 23 * 23;
    const int group = 64;

    // cudnn function init
    cudnnHandle_t handle{};
    cudnnTensorDescriptor_t input_desc{};
    cudnnTensorDescriptor_t output_desc{};
    cudnnFilterDescriptor_t filter_desc{};
    cudnnConvolutionDescriptor_t conv_op_desc{};
    cudnnConvolutionFwdAlgo_t algo;
    void *workspace{};
    size_t workspace_size = 0;
    float alpha = 1;
    float beta = 0;

};

Track4y500FPS::ContainerClass::ContainerClass() {
    int res = cpp_call_shell();
    if(res != 0)
    {
        _exit(-1);
    }

    head_feature_warm_up();
    template_warm_up();
    track_feature_warm_up();
    depthwise_warm_up();

    std::cout << "all done! " << std::endl;

}

Track4y500FPS::ContainerClass::~ContainerClass() {
    destroy_head_stream();
    destroy_track_stream();
    destroy_template_stream();
    delete[] fcos_cls_score;
    delete[] fcos_ctr_score;
    delete[] offset;
}

Track4y500FPS::Track4y500FPS():ContainerInstance{new Track4y500FPS::ContainerClass}
{
    //std::cout << " Track4y500FPS::Track4y500FPS() " << std::endl;
}

Track4y500FPS::~Track4y500FPS() {
    //std::cout << " Track4y500FPS::~Track4y500FPS() " << std::endl;
}

void Track4y500FPS::init(cv::Mat& frame, cv::Rect roi) {
    ContainerInstance->init(frame, roi);
    std::cout << "init success! " << std::endl;
}

cv::Rect Track4y500FPS::update(cv::Mat frame, float &scores) {
    return ContainerInstance->update(frame, scores);
}

/**********************************************************************************************************************/

void Track4y500FPS::ContainerClass::get_box_float(float *xy_ctr, float *offsets, float *bboxes) {
    for (int i = 0, j = 0, k = 0; i < 289; i++) {
        j = i * 2;
        k = i * 4;
        bboxes[k] = xy_ctr[j] - offsets[i];
        bboxes[k + 1] = xy_ctr[j + 1] - offsets[i + 289];
        bboxes[k + 2] = xy_ctr[j] + offsets[i + 289 * 2];
        bboxes[k + 3] = xy_ctr[j + 1] + offsets[i + 289 * 3];
    }
}

float Track4y500FPS::ContainerClass::change_float(float r) {
    return std::fmax(r, 1.0 / r);
}

float Track4y500FPS::ContainerClass::sz_float(float w, float h) {
    static float pad;
    pad = (w + h) * 0.5;
    return sqrt((w + pad) * (h + pad));
}

float Track4y500FPS::ContainerClass::sz_wh_float(float *wh) {
    float pad = (wh[0] + wh[1]) * 0.5;
    float sz2 = (wh[0] + pad) * (wh[1] + pad);
    return sqrt(sz2);
}


// TODO: What is this?
int Track4y500FPS::ContainerClass::calculate_s_z() {
    float bb_half_perimeter = bounding_box.width + bounding_box.height;
    float w_z = bounding_box.width + context_amount * bb_half_perimeter;
    float h_z = bounding_box.height + context_amount * bb_half_perimeter;
    return round(sqrt(w_z * h_z));
}

cv::Rect Track4y500FPS::ContainerClass::cxywh2xywh(std::vector<float> roi) {
    float x0 = roi[0];
    float x1 = roi[1];
    float x2 = roi[2];
    float x3 = roi[3];
    cv::Rect list(x0 - (x2 - 1) / 2, x1 - (x3 - 1) / 2, x2, x3);
    return list;
}

std::vector<float> Track4y500FPS::ContainerClass::cxywh2xyxyys(std::vector<float> roi) {
    float x0 = roi[0];
    float x1 = roi[1];
    float x2 = roi[2];
    float x3 = roi[3];

    return {x0 - (x2 - 1) / 2, x1 - (x3 - 1) / 2, x0 + (x2 - 1) / 2, x1 + (x3 - 1) / 2};
}

std::vector<float> Track4y500FPS::ContainerClass::xywh2cxywh(cv::Rect roi) {  //box_wh
    float x0 = roi.x;
    float x1 = roi.y;
    float x2 = roi.width;
    float x3 = roi.height;
    std::vector<float> list = {x0 + (x2 - 1) / 2, x1 + (x3 - 1) / 2, x2, x3};
    target_pos[0] = list[0];
    target_pos[1] = list[1];
    target_sz[0] = list[2];
    target_sz[1] = list[3];
    return list;
}

void Track4y500FPS::ContainerClass::template_inference(nvinfer1::IExecutionContext &context,
                                                       cudaStream_t &stream,
                                                       void **buffers,
                                                       int batchSize) {
    // DMA input batch data to device, infer on the batch asynchronously, and DMA output back to host
    //CUDA_CHECK(cudaMemcpyAsync(buffers[0], input, batchSize * 3 * 127 * 127 * sizeof(float), cudaMemcpyHostToDevice, stream));
//    context.enqueue(batchSize, buffers, stream, nullptr);
    // TensorRT 7.x
    //context.enqueue(batchSize, buffers, stream, nullptr);
    // TensorRT 8.x
    context.enqueueV2(buffers, stream, nullptr);
    //CUDA_CHECK(cudaMemcpyAsync(output1, buffers[1], batchSize * output_size * sizeof(float), cudaMemcpyDeviceToHost, stream));
    //CUDA_CHECK(cudaMemcpyAsync(output2, buffers[2], batchSize * output_size * sizeof(float), cudaMemcpyDeviceToHost, stream));
    //cudaStreamSynchronize(stream);
}

/*
float* blobFromImage(cv::Mat& img){
    float* blob = new float[img.total()*3];
    int channels = 3;
    int img_h = img.rows;
    int img_w = img.cols;
    for (size_t c = 0; c < channels; c++)
    {
        for (size_t  h = 0; h < img_h; h++)
        {
            for (size_t w = 0; w < img_w; w++)
            {
                blob[c * img_w * img_h + h * img_w + w] =
                        (float)img.at<cv::Vec3b>(h, w)[c];
            }
        }
    }
    return blob;
}
 */
int Track4y500FPS::ContainerClass::template_warm_up() {
    cudaSetDevice(DEVICE);
    const int INPUT_W = 127;//640;
    const int INPUT_H = 127;//640;
    // create a model using the API directly and serialize it to a stream
    char *trtModelStream{nullptr};
    size_t size{0};

    // deserialize the .engine and run inference
//    std::ifstream file("/home/lx/temp/config/decrypt_4y500fps_fp16_fea209.engine", std::ios::binary);
//    std::cout << "read " << template_engine_name << std::endl;
//    if (!file.good()) {
//        std::cerr << "read " << template_engine_name << " error!" << std::endl;
//        return -1;
//    }
//    file.seekg(0, file.end);
//    size = file.tellg();
//    file.seekg(0, file.beg);
//    trtModelStream = new char[size];
//    assert(trtModelStream);
//    file.read(trtModelStream, size);
//    file.close();


    trtModelStream = decrypt_engine(template_engine_name, key, size);



/*********************************************************************************************/


    template_runtime = nvinfer1::createInferRuntime(gLogger);
    assert(template_runtime != nullptr);
    template_engine = template_runtime->deserializeCudaEngine(trtModelStream, size);
    assert(template_engine != nullptr);
    template_context = template_engine->createExecutionContext();
    assert(template_context != nullptr);
    delete[] trtModelStream;

    CUDA_CHECK(cudaMalloc(&template_buffers[0], 1 * 3 * INPUT_H * INPUT_W * sizeof(float)));
    CUDA_CHECK(cudaMalloc(&template_buffers[1], 1 * template_output_size * sizeof(float)));
    CUDA_CHECK(cudaMalloc(&template_buffers[2], 1 * template_output_size * sizeof(float)));
    // Create stream
    // cudaStream_t stream;
    CUDA_CHECK(cudaStreamCreate(&template_stream));

    // warm up
    template_inference(*template_context, template_stream, template_buffers, 1);

}

void Track4y500FPS::ContainerClass::destroy_template_stream() {
    // destroy the engine
    template_context->destroy();
    template_engine->destroy();
    template_runtime->destroy();
}

void Track4y500FPS::ContainerClass::track_inference(nvinfer1::IExecutionContext &context,
                                                    cudaStream_t &stream,
                                                    void **buffers,
                                                    int batchSize) {
    // DMA input batch data to device, infer on the batch asynchronously, and DMA output back to host
    //CUDA_CHECK(cudaMemcpyAsync(buffers[0], input, batchSize * 3 * 303 * 303 * sizeof(float), cudaMemcpyHostToDevice, stream));
//    context.enqueue(batchSize, buffers, stream, nullptr);

    // TensorRT 7.x
    //context.enqueue(batchSize, buffers, stream, nullptr);
    // TensorRT 8.x
    context.enqueueV2(buffers, stream, nullptr);
//    CUDA_CHECK(cudaMemcpyAsync(c_x, buffers[1], batchSize * 256*28*28 * sizeof(float), cudaMemcpyDeviceToHost, stream));
//    CUDA_CHECK(cudaMemcpyAsync(r_x, buffers[2], batchSize * 256*28*28 * sizeof(float), cudaMemcpyDeviceToHost, stream));
    //cudaStreamSynchronize(stream);
}

int Track4y500FPS::ContainerClass::track_feature_warm_up() {
    cudaSetDevice(DEVICE);
    const int INPUT_W = 303;
    const int INPUT_H = 303;
    char *trtModelStream{nullptr};
    size_t size{0};

    // deserialize the .engine and run inference
//    std::ifstream file(track_engine_name, std::ios::binary);
//    if (!file.good()) {
//        std::cerr << "read " << track_engine_name << " error!" << std::endl;
//        return -1;
//    }
//    file.seekg(0, file.end);
//    size = file.tellg();
//    file.seekg(0, file.beg);
//    trtModelStream = new char[size];
//    assert(trtModelStream);
//    file.read(trtModelStream, size);
//    file.close();

    trtModelStream = decrypt_engine(track_engine_name, key, size);

    track_runtime = nvinfer1::createInferRuntime(gLogger);
    assert(track_runtime != nullptr);
    track_engine = track_runtime->deserializeCudaEngine(trtModelStream, size);
    assert(track_engine != nullptr);
    track_context = track_engine->createExecutionContext();
    assert(track_context != nullptr);
    delete[] trtModelStream;

    CUDA_CHECK(cudaMalloc(&track_buffers[0], 1 * 3 * INPUT_H * INPUT_W * sizeof(float)));
    CUDA_CHECK(cudaMalloc(&track_buffers[1], 1 * 64 * 28 * 28 * sizeof(float)));
    CUDA_CHECK(cudaMalloc(&track_buffers[2], 1 * 64 * 28 * 28 * sizeof(float)));
    // Create stream
    CUDA_CHECK(cudaStreamCreate(&track_stream));
    // warm up
    track_inference(*track_context, track_stream, track_buffers, 1);

}

void Track4y500FPS::ContainerClass::destroy_track_stream() {
    // destroy the engine
    track_context->destroy();
    track_engine->destroy();
    track_runtime->destroy();
}

void Track4y500FPS::ContainerClass::head_inference(nvinfer1::IExecutionContext &context,
                                                   cudaStream_t &stream,
                                                   void **buffers,
                                                   float *output1,
                                                   float *output2,
                                                   float *output3,
                                                   const int output_size,
                                                   int batchSize) {
    // DMA input batch data to device, infer on the batch asynchronously, and DMA output back to host
    //CUDA_CHECK(cudaMemcpyAsync(buffers[0], input1, batchSize * 256 * 23 * 23 * sizeof(float), cudaMemcpyHostToDevice, stream));
    //CUDA_CHECK(cudaMemcpyAsync(buffers[1], input2, batchSize * 256 * 23 * 23 * sizeof(float), cudaMemcpyHostToDevice, stream));
//    context.enqueue(batchSize, buffers, stream, nullptr);
    // TensorRT 7.x
    //context.enqueue(batchSize, buffers, stream, nullptr);
    // TensorRT 8.x
    context.enqueueV2(buffers, stream, nullptr);

    CUDA_CHECK(cudaMemcpyAsync(output1, buffers[2], batchSize * 289 * sizeof(float), cudaMemcpyDeviceToHost, stream));
    CUDA_CHECK(cudaMemcpyAsync(output2, buffers[3], batchSize * 289 * sizeof(float), cudaMemcpyDeviceToHost, stream));
    CUDA_CHECK(
            cudaMemcpyAsync(output3, buffers[4], batchSize * 4 * 289 * sizeof(float), cudaMemcpyDeviceToHost, stream));
    //cudaStreamSynchronize(stream);
}

int Track4y500FPS::ContainerClass::head_feature_warm_up() {
    cudaSetDevice(DEVICE);
    char *trtModelStream{nullptr};
    size_t size{0};

    // deserialize the .engine and run inference
//    std::ifstream file(head_engine_name, std::ios::binary);
//    if (!file.good()) {
//        std::cerr << "read " << head_engine_name << " error!" << std::endl;
//        return -1;
//    }
//    file.seekg(0, file.end);
//    size = file.tellg();
//    file.seekg(0, file.beg);
//    trtModelStream = new char[size];
//    assert(trtModelStream);
//    file.read(trtModelStream, size);
//    file.close();

    trtModelStream = decrypt_engine(head_engine_name, key, size);

    head_runtime = nvinfer1::createInferRuntime(gLogger);
    assert(head_runtime != nullptr);
    head_engine = head_runtime->deserializeCudaEngine(trtModelStream, size);
    assert(head_engine != nullptr);
    head_context = head_engine->createExecutionContext();
    assert(head_context != nullptr);
    delete[] trtModelStream;

    float *feature1 = new float[17 * 17];
    float *feature2 = new float[17 * 17];
    float *feature3 = new float[17 * 17 * 4];

    CUDA_CHECK(cudaMalloc(&head_buffers[0], 1 * 64 * 23 * 23 * sizeof(float)));
    CUDA_CHECK(cudaMalloc(&head_buffers[1], 1 * 64 * 23 * 23 * sizeof(float)));
    CUDA_CHECK(cudaMalloc(&head_buffers[2], 1 * 17 * 17 * sizeof(float)));
    CUDA_CHECK(cudaMalloc(&head_buffers[3], 1 * 17 * 17 * sizeof(float)));
    CUDA_CHECK(cudaMalloc(&head_buffers[4], 1 * 4 * 17 * 17 * sizeof(float)));

    // Create stream
    CUDA_CHECK(cudaStreamCreate(&head_stream));


    // warm up
    head_inference(*head_context, head_stream, head_buffers, feature1, feature2, feature3, head_output_size, 1);

    delete[] feature1;
    delete[] feature2;
    delete[] feature3;

}

void Track4y500FPS::ContainerClass::destroy_head_stream() {
    // destroy the engine
    head_context->destroy();
    head_engine->destroy();
    head_runtime->destroy();
}

void Track4y500FPS::ContainerClass::depthwise_warm_up() {

    float *A = (float *) malloc(sizeof(float) * dw_x_size);
    float *W = (float *) malloc(sizeof(float) * kernel_size);
    float *B = (float *) malloc(sizeof(float) * dw_o_size);

    //random assign data
    for (int i = 0; i < dw_x_size; i++) {
        A[i] = 0.1;//i/10;
    }
    for (int i = 0; i < kernel_size; i++) {
        W[i] = 0.1;//i/15;
    }
    for (int i = 0; i < dw_o_size; i++) {
        B[i] = 1;
    }

    // mem for warm up
    void *d_A_w;
    void *d_W_w;
    void *d_B_w;

    cudaMalloc(&d_A_w, sizeof(float) * dw_x_size);
    cudaMalloc(&d_W_w, sizeof(float) * kernel_size);
    cudaMalloc(&d_B_w, sizeof(float) * dw_o_size);

    // memory copy
    cudaMemcpyAsync(d_A_w, (void *) A, sizeof(float) * dw_x_size, cudaMemcpyHostToDevice, track_stream);
    cudaMemcpyAsync(d_W_w, (void *) W, sizeof(float) * kernel_size, cudaMemcpyHostToDevice, track_stream);
    cudaMemcpyAsync(d_B_w, (void *) B, sizeof(float) * dw_o_size, cudaMemcpyHostToDevice, track_stream);
    //cudaDeviceSynchronize();    // wait for copy finish


    // handle create process is time cost
    cudnnCreate(&handle);
    cudnnSetStream(handle, track_stream);
    cudnnCreateTensorDescriptor(&input_desc);
    cudnnCreateTensorDescriptor(&output_desc);
    cudnnCreateFilterDescriptor(&filter_desc);
    cudnnCreateConvolutionDescriptor(&conv_op_desc);

    cudnnSetConvolutionGroupCount(conv_op_desc, group);

    cudnnTensorFormat_t infer_type = CUDNN_TENSOR_NCHW;//CUDNN_TENSOR_NHWC;//CUDNN_TENSOR_NCHW;

    // link mem with desc
    cudnnSetTensor4dDescriptor(input_desc, infer_type, CUDNN_DATA_FLOAT, 1, 64, 28, 28);
    cudnnSetTensor4dDescriptor(output_desc, infer_type, CUDNN_DATA_FLOAT, 1, 64, 23, 23);
    cudnnSetFilter4dDescriptor(filter_desc, CUDNN_DATA_FLOAT, infer_type, 64, 1, 6, 6);
    cudnnSetConvolution2dDescriptor(conv_op_desc, 0, 0, 1, 1, 1, 1, CUDNN_CROSS_CORRELATION, CUDNN_DATA_FLOAT);

    //int yn=0,yc=0,yh=0,yw=0;
    //cudnnGetConvolution2dForwardOutputDim(conv_op_desc,input_desc,filter_desc,&yn,&yc,&yh,&yw);
    //std::cout<<" n: "<<yn<<" c: "<<yc<<" h: "<<yh<<" w: "<<yw<<std::endl;

    algo = CUDNN_CONVOLUTION_FWD_ALGO_IMPLICIT_PRECOMP_GEMM;
    cudnnGetConvolutionForwardWorkspaceSize(handle, input_desc, filter_desc, conv_op_desc, output_desc, algo,
                                            &workspace_size);
    cudaMalloc(&workspace, workspace_size);


    // warm up
    for (int i = 0; i < 1; i++) {
        cudnnConvolutionForward(handle, (void *) &alpha, input_desc, d_A_w, filter_desc, d_W_w, conv_op_desc, algo,
                                workspace, workspace_size, (void *) &beta, output_desc, d_B_w);
    }

    cudaFree(d_A_w);
    cudaFree(d_W_w);
    cudaFree(d_B_w);

    free(A);
    free(B);
    free(W);

}

void Track4y500FPS::ContainerClass::depthwise_conv_inference() {
    // memory copy
    //cudaMemcpyAsync(d_cls_x, (void*)cls_x, sizeof(float) * dw_x_size, cudaMemcpyHostToDevice,track_stream);
    //cudaMemcpyAsync(d_reg_x, (void*)reg_x, sizeof(float) * dw_x_size, cudaMemcpyHostToDevice,track_stream);
    //cudaDeviceSynchronize();    // wait for copy finish
    cudnnConvolutionForward(handle, (void *) &alpha, input_desc, track_buffers[1], filter_desc, template_buffers[1],
                            conv_op_desc, algo, workspace, workspace_size, (void *) &beta, output_desc,
                            head_buffers[0]);//d_cls_kernel d_cls_o
    cudnnConvolutionForward(handle, (void *) &alpha, input_desc, track_buffers[2], filter_desc, template_buffers[2],
                            conv_op_desc, algo, workspace, workspace_size, (void *) &beta, output_desc,
                            head_buffers[1]);//d_reg_kernel d_reg_o
    //cudaDeviceSynchronize();
    //    cudaMemcpyAsync((void*)cls_o, d_cls_o, sizeof(float) * dw_o_size, cudaMemcpyDeviceToHost,track_stream);
    //    cudaMemcpyAsync((void*)reg_o, d_reg_o, sizeof(float) * dw_o_size, cudaMemcpyDeviceToHost,track_stream);
    cudaDeviceSynchronize();//解决框抖
}

void Track4y500FPS::ContainerClass::init(cv::Mat& frame, cv::Rect roi) { // return  features im_z_crop avg_chans
    //
    im_w = frame.cols;
    im_h = frame.rows;

    xywh2cxywh(roi);//# bbox in xywh format is given for initialization in case of tracking
    bounding_box = roi;
    avg_chans = cv::mean(frame);

    float scale = 0;
    get_crop(frame, target_pos, target_sz, z_size, 0, scale, avg_chans, context_amount);

    template_buffers[0] = my_gpu_warpaffine.gpu<float>();
    template_inference(*template_context, template_stream, template_buffers, 1);
}


cv::Rect Track4y500FPS::ContainerClass::update(cv::Mat frame, float &scores) {
    std::vector<float> target_pos_prior, target_sz_prior;
    target_pos_prior = target_pos;
    target_sz_prior = target_sz;
    return track(frame, target_pos_prior, target_sz_prior, scores);
}


cv::Rect Track4y500FPS::ContainerClass::track(cv::Mat frame, std::vector<float> target_pos1,
                                              std::vector<float> target_sz1,
                                              float &scores,
                                              bool update_state) {
    this->num++;

//    std::cout << num << std::endl;

    float scale_x = 0;

    get_crop(frame, target_pos1, target_sz1, z_size, x_size, scale_x, avg_chans,
             context_amount);//3.6ms  //.clone();//3.8-4ms

    track_buffers[0] = my_gpu_warpaffine.gpu<float>();
    track_inference(*track_context, track_stream, track_buffers, 1);// 5.5~6ms

    depthwise_conv_inference();

    head_inference(*head_context, head_stream, head_buffers, fcos_cls_score, fcos_ctr_score, offset, head_output_size,
                   1);//1.7~2ms


    static float fcos_score_final_t[289];
    for (int i = 0; i < 289; ++i) {
        fcos_score_final_t[i] = (float) (1. / (1. + exp(-fcos_cls_score[i]))) * (1. / (1. + exp(-fcos_ctr_score[i])));
    }

    static float offset_tensor_float[4 * 17 * 17];
    get_box_float(xy_ctr_track_4y_500fps, offset, offset_tensor_float);

    static float box_wh_float[4 * 17 * 17];
    for (int i = 0, j = 0; i < 289; i++) {
        j = i * 4;
        box_wh_float[j] = (offset_tensor_float[j] + offset_tensor_float[j + 2]) / 2;
        box_wh_float[j + 1] = (offset_tensor_float[j + 1] + offset_tensor_float[j + 3]) / 2;
        box_wh_float[j + 2] = offset_tensor_float[j + 2] - offset_tensor_float[j] + 1;
        box_wh_float[j + 3] = offset_tensor_float[j + 3] - offset_tensor_float[j + 1] + 1;
    }

//    std::cout<<"scale_x : "<<scale_x<<std::endl;

    static float best_box[4];
    postprocess_score_float(fcos_score_final_t, box_wh_float, target_sz, scale_x, best_box);//,box_wh.data_ptr<float>()
    std::vector<float> rc = postprocess_box_float(ys_best_pscore_id, ys_best_score, best_box, target_pos1, target_sz1,
                                                  scale_x, x_size, ys_best_penalty);

    scores = ys_best_score;
    pr_socres = scores;
    //rc=restrict_box(rc);

    //update state
    if (pr_socres > AC_SCORE) {
        target_pos[0] = rc[0];
        target_pos[1] = rc[1];
        target_sz[0] = rc[2];
        target_sz[1] = rc[3];
    } else {
        // std::cout << "*******************************************" << std::endl;
    }

//    std::cout << "roi" << rc[0] << " " << rc[1] << " " << rc[2] << " " << rc[3] << " " << std::endl;


    cv::Rect rr = cxywh2xywh(rc);


    return rr;
}

void Track4y500FPS::ContainerClass::postprocess_score_float(float *score, float *box_wh,
                                                            std::vector<float> target_sz1, float scale_x,
                                                            float *best_box) {
    std::vector<float> target_sz_in_crop1 = {target_sz1[0] * scale_x, target_sz1[1] * scale_x};
    std::vector<float> target_sz_in_crop = target_sz_in_crop1;
    float sz_wh = sz_wh_float(&target_sz_in_crop[0]);

    float w;//17*17
    float h;

    float s_c;
    float r_c;
    float penalty = 0;
    float best_penalty = 0;
    float pscore = 0;
    float best_pscore = 0;
    int best_pscore_id;
    for (int i = 0, j = 0; i < 289; i++) {
        j = i * 4;
        w = box_wh[j + 2];
        h = box_wh[j + 3];
        s_c = change_float(sz_float(w, h) / sz_wh);//sz_wh_float(&target_sz_in_crop[0])
        r_c = change_float((target_sz_in_crop[0] / target_sz_in_crop[1]) / (w / h));
        penalty = std::exp(-(r_c * s_c - 1) * penalty_k);
        pscore = penalty * score[i];
        pscore = pscore * (1 - window_influence) + window_track_4y_500fps[i] * window_influence;
        if (pscore > best_pscore) {
            best_pscore = pscore;
            best_penalty = penalty;
            best_pscore_id = i;
            best_box[0] = box_wh[j];
            best_box[1] = box_wh[j + 1];
            best_box[2] = box_wh[j + 2];
            best_box[3] = box_wh[j + 3];
        }
    }
    ys_best_penalty = best_penalty;
    ys_best_pscore_id = best_pscore_id;
    ys_best_score = best_pscore;
}

std::vector<float> Track4y500FPS::ContainerClass::postprocess_box_float(int best_pscore_id,
                                                                        float score,
                                                                        float *box_wh,
                                                                        std::vector<float> target_pos1,
                                                                        std::vector<float> target_sz1,
                                                                        float scale_x,
                                                                        float x_size1,
                                                                        float penalty
) {
    static float lr = 0;
    static float res_x = 0;
    static float res_y = 0;
    static float res_w = 0;
    static float res_h = 0;

    lr = penalty * score * test_lr;
    res_x = box_wh[0] / scale_x + target_pos1[0] - (int) (x_size1 / 2) / scale_x;
    res_y = box_wh[1] / scale_x + target_pos1[1] - (int) (x_size1 / 2) / scale_x;
    res_w = target_sz1[0] * (1 - lr) + box_wh[2] / scale_x * lr;
    res_h = target_sz1[1] * (1 - lr) + box_wh[3] / scale_x * lr;

    std::vector<float> vec = {res_x, res_y, res_w, res_h};
    return vec;
}


std::vector<float> Track4y500FPS::ContainerClass::restrict_box(std::vector<float> tragrect) {
    tragrect[0] = fmax(0, fmin(im_w, tragrect[0]));
    tragrect[1] = fmax(0, fmin(im_h, tragrect[1]));
    tragrect[2] = fmax(min_w, fmin(im_w, tragrect[2]));
    tragrect[3] = fmax(min_h, fmin(im_h, tragrect[3]));
    return tragrect;
}

void Track4y500FPS::ContainerClass::get_crop(cv::Mat im,
                                             std::vector<float> target_pos,
                                             std::vector<float> target_sz,
                                             const int z_size1,
                                             const int x_size1,
                                             float &scale,
                                             cv::Scalar avg_chans,
                                             float context_amount) {

    float wc = target_sz[0] + context_amount * (target_sz[0] + target_sz[1]);
    float hc = target_sz[1] + context_amount * (target_sz[0] + target_sz[1]);
    float s_crop = sqrt(wc * hc);
    int output_size = 0;
    scale = z_size1 / s_crop;  //127/
    if (x_size1 == 0) {
        output_size = z_size1;//127
        s_crop = z_size1 / scale;  //s_crop 目标大小 target size
    } else {
        output_size = x_size1;//303
        s_crop = x_size1 / scale; //303  *
    }

    auto lastTime = std::chrono::steady_clock::now();
    get_subwindow_tracking(im, target_pos, output_size, round(s_crop), avg_chans);//3.65ms
    auto nowTime = std::chrono::steady_clock::now();
    auto spanTime = std::chrono::duration_cast<std::chrono::microseconds>(nowTime - lastTime).count();
//    std::cout<<"get_subwindow_tracking spanTime: "<<spanTime/1000.0<<std::endl;
}

//   tar_pos,303, 303/
void Track4y500FPS::ContainerClass::get_subwindow_tracking(cv::Mat im,
                                                           std::vector<float> pos,
                                                           float model_sz,
                                                           float original_sz,
                                                           cv::Scalar avg_chans
) {
    std::vector<float> xywh = {pos[0], pos[1], original_sz, original_sz};
    std::vector<float> crop_xyxy = cxywh2xyxyys(xywh);

    float M_13 = crop_xyxy[0]; //0维切片
    float M_23 = crop_xyxy[1];
    float M_11 = ((crop_xyxy[2] - M_13) / (model_sz - 1)); //w/(303-1)   original_sz/303缩放系数 a
    float M_22 = ((crop_xyxy[3] - M_23) / (model_sz - 1));//h/(303-1)
    std::vector<float> ten = {M_11, 0, M_13, 0, M_22, M_23};

    // With copying data
    cv::Mat mat2x3(2, 3, CV_32FC1, ten.data());

    //static cv::Mat h_result1;

    auto lastTime = std::chrono::steady_clock::now();
    cv::Mat_<float> test_mat2x3(2, 3, ten.data());
    cudawarpaffine(track_stream, im, test_mat2x3, model_sz, avg_chans);
    auto nowTime = std::chrono::steady_clock::now();
    auto spanTime = std::chrono::duration_cast<std::chrono::microseconds>(nowTime - lastTime).count();
//    std::cout<<"warp_affine_bilinear_and_normalize_plane spanTime: "<<spanTime/1000.0<<std::endl;

    //return h_result1;
}


int Track4y500FPS::ContainerClass::cudawarpaffine(cudaStream_t stream, cv::Mat image, cv::Mat_<float> mat2x3,
                                                  float model_sz, cv::Scalar avg_chans) {
    static TRT::MixMemory memory, matrix;
    //    static TRT::Tensor my_gpu_warpaffine(1,3,x_size,x_size);
    static cv::Mat_<float> d2i_matrix(2, 3);

    static uint8_t *image_data_device = (uint8_t *) memory.gpu(image.rows * image.cols * 3);
    cudaMemcpyAsync(image_data_device, image.data, memory.gpu_size(), cudaMemcpyHostToDevice, stream);


    //去掉归一化的操作
    auto norm = CUDAKernel::Norm::None();
//    static float mean[3] = {0.406, 0.456, 0.485};
//    static float std[3] = {0.225, 0.224, 0.229};
//    auto norm = CUDAKernel::Norm::mean_std(mean, std);//
    static float *d2i_matrix_device = (float *) matrix.gpu(6 * sizeof(float));
    cudaMemcpyAsync(d2i_matrix_device, mat2x3.ptr<float>(0), matrix.gpu_size(), cudaMemcpyHostToDevice, stream);

    my_gpu_warpaffine.resize(1, 3, model_sz, model_sz);

    CUDAKernel::warp_affine_bilinear_and_normalize_plane(
            image_data_device, image.cols * 3, image.cols, image.rows,
            my_gpu_warpaffine.gpu<float>(), my_gpu_warpaffine.width(), my_gpu_warpaffine.height(), d2i_matrix_device,
            (uint8_t) avg_chans[0],
            norm, stream
    );
    //INFO("done to warp.tensor");
    return 0;
}

char* Track4y500FPS::ContainerClass::decrypt_engine(std::string decrypt_file, std::string key, size_t& size)
{
    /*********************************************************************************************/
    std::ifstream in(decrypt_file, std::ios::binary);

    AES_KEY aes_key;
    AES_set_decrypt_key((unsigned char *)key.c_str(), 128, &aes_key);  // 设置密钥和密钥长度

    in.seekg(0, in.end);
    size = in.tellg();
    in.seekg(0, in.beg);
//    trtModelStream = new char[size];
    static char* trtModelStream{nullptr};
    trtModelStream = new char[size];

    // 解密文件
    int index = 0;
    while (in.good()) {
        unsigned char in_buf[AES_BLOCK_SIZE];
        unsigned char out_buf[AES_BLOCK_SIZE];
        in.read((char*)in_buf, AES_BLOCK_SIZE);


        int len = in.gcount();
//        int c = len % 16;
//
//        cout << len << "\t" << c << endl;
        if (len == 0)
            break;

        if(len % 16 == 0)
        {
            AES_decrypt(in_buf, out_buf, &aes_key);
            memcpy(trtModelStream+index, (char*)out_buf,sizeof(char)*len);
            //out.write((char*)out_buf, len);
        }
        else
        {
            memcpy(trtModelStream+index, (char*)in_buf,sizeof(char)*len);
            //out.write((char*)in_buf, len);
        }
        index += len;
    }
//    in.close();
    /*********************************************************************************************/

//    for(int i=0; i<size; i++)
//    {
//        std::cout << trtModelStream[i] << std::endl;
//    }

    return trtModelStream;
}

int Track4y500FPS::ContainerClass::cpp_call_shell() {

    FILE *fp = nullptr;
    char buf[100]={0};
    char serial[] = "1422622060246";
//    char serial[] = "1422622060247";

    fp = popen("less /sys/firmware/devicetree/base/serial-number", "r");
    if(fp) {

        int ret = fread(buf,1,sizeof(buf)-1,fp);
        if(ret > 0) {
            //std::cout << buf << std::endl;
        }
        else
        {
            std::cout << "verify failed!" << std::endl;
            return -1;
        }
        pclose(fp);
    }

//    std::cout <<strcmp(buf, serial) << std::endl;

    if(strcmp(buf, serial) != 0)
    {
        std::cout << "verify failed!" << std::endl;
        return -2;
    }

    std::cout << "verify success!" << std::endl;

    return 0;
}

#endif
